#include "main.h"  
#include "stdio.h"


int              LIN_RX_TimOut;
extern int       Temp;
extern int       CF_RequestNum;
extern LIN_MSG*  pSignalMsg;   
extern LIN_MSG*  pDiagnoseMsg; 
LIN_MSG          LINRxDataBuf[LIN_BUFFER_SIZE];
LIN_RxState      LIN_RxStateGet = BREAK_GET; 
LIN_MSG_IDType   FrameIDType[64] = {MASTER_BREAK};  

extern int Temp2;

//LIN接收缓冲区
LIN_BUFFER   LIN_RxDataBuff = {
	.Head = 0,
	.Tail = 0,
	.Length = 0,
	.BufOutcnt = 0	
};

/**
  * @brief  LIN总线错误输出
  * @param  ErrorCode：错误代码
  * @retval None
  */
void LIN_ErrorCode(LIN_ERROR_Code ErrorCode)
{
	switch (ErrorCode){
		case LIN_OK:     OLED_ShowString(1,6,"OK         ");break;				
		case SYNC_ERR:   OLED_ShowString(1,6,"SYNC_ERR   ");break;						
		case PID_ERR:    OLED_ShowString(1,6,"PID_ERR    ");break;				
		case CHECK_ERR:  OLED_ShowString(1,6,"CHECK_ERR  ");break;				
		case NO_RESPONES:OLED_ShowString(1,6,"NO_RESPONES");break;							
		case FORMAT_ERR: OLED_ShowString(1,6,"FORMAT_ERR ");break;
		default:  break;       						
	}
}

LIN_ERROR_Code LIN_Process(LIN_BUFFER* pLINRxBuf)
{
	LIN_ERROR_Code ErrCode = FIFO_VOID;
	LIN_MSG* pLINMsg = NULL;
	
	if (LIN_RingBUF_Read(pLINRxBuf, &pLINMsg) != 1){
		if (pLINMsg->Sync == 0x55){	
			uint8_t PID = LIN_GetPID(pLINMsg->FrameID);
			if (pLINMsg->PID == PID){
				if (pLINMsg->DataLen <= 8){
					if (pLINMsg->DataLen > 0){
						uint8_t Checksum = ~LIN_GetChecksum(pLINMsg->PID, pLINMsg->Data, pLINMsg->DataLen);
						Checksum+= pLINMsg->Checksum;
							if (Checksum == 0xFF){								
								ErrCode = LIN_OK;  //OK
								pSignalMsg = pLINMsg;																							
							}else{								
								ErrCode = CHECK_ERR; //校验和错误									
							}						
						}else{
							ErrCode = NO_RESPONES; //无响应	
						}					
				}else{
					ErrCode = FORMAT_ERR;  //格式错误							
				}				
			}else{
				ErrCode = PID_ERR;	//PID错误	
			}			
		}else{
			ErrCode = SYNC_ERR;   //同步段错误
		} 
	}else{
		ErrCode = FIFO_VOID;   //无数据
	}
	return ErrCode;
}

void LIN_TimOutCmd(TIM_TypeDef* TIMx, FunctionalState NewState)
{
	TIM_Cmd(TIMx,NewState);    //使能定时器计数器	
}

void LIN_TimeProcess(void)
{
	if (LIN_RX_TimOut > 0){ 	
		LIN_RX_TimOut--;
		if (LIN_RX_TimOut == 0){   //LIN_RX_TimOut >= 12*10000/USART1_Buad			
			LIN_MSG* pLINMsg = LIN_RingBUF_GetMsg(&LIN_RxDataBuff);
			pLINMsg->DataLen = (pLINMsg->DataLen <= 0)?0:pLINMsg->DataLen-1;		
			LIN_RingBUF_Write(&LIN_RxDataBuff);				
			LIN_RxStateGet = BREAK_GET;
			LIN_TimOutCmd(TIM3,DISABLE);
			Temp = Temp2; //复位超时计数			
		}			
	}	
}



/**
  * @brief  定时器3中断函数：LIN接收超时中断
  * @param  None
  * @retval None
  */
void TIM3_IRQHandler(void)  
{	
	if (TIM_GetITStatus(TIM3,TIM_IT_Update) == SET){ //定时器更新中断 	
		LIN_TimeProcess();
	    TIM_ClearITPendingBit(TIM3,TIM_IT_Update);   				
	}
}


/**
  * @brief LIN_PID校验函数		
  * @param ID(FrameID)：帧ID(0 ~ 63) 
  * P0(bit6) =   ID0 ^ ID1 ^ ID2 ^ ID4   <==>  (偶校验：操作数中1的个数为偶数，校验位为0，1的个数为奇数校验位为1)
  * P1(bit7) = ~(ID1 ^ ID3 ^ ID4 ^ ID5)  <==>  (奇校验：操作数中1的个数为奇数，校验位为0，1的个数为偶数校验位为1)
  * @retval 返回PID
  */
uint8_t LIN_GetPID(uint8_t ID)  
{
	uint8_t PID = 0,P0 = 0,P1 = 0;	
	P0 = (((ID>>0)^(ID>>1)^(ID>>2)^(ID>>4))&0x01)<<6; //偶校验位           			
	P1 = ((~((ID>>1)^(ID>>3)^(ID>>4)^(ID>>5)))&0x01)<<7; //奇校验位	
	PID = (ID|P0|P1);	
	return PID;   
}

/**
  * @brief  LIN同步间隔段发送		
  * @param  USARTx：串口号
  * @retval 无
  */
void LIN_SendBreak(USART_TypeDef* USARTx)
{
	USART_SendBreak(USARTx);
}

/**
  * @brief  LIN发送字节	
  * @param  USARTx：串口号，pData：数据指针，Length：数据长度
  * @retval 无
  */
void LIN_SendBytes(USART_TypeDef* USARTx,uint8_t* pData,uint8_t DataLen)
{
	for (uint8_t i = 0; i < DataLen; i++){
		USART_SendData(USARTx,*pData++);
		while (USART_GetFlagStatus(USARTx,USART_FLAG_TXE) == RESET);			
	}
	while (USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);		
}

/**
  * @brief  LIN协议规定校验和长度为1个字节			
  * @param  PID：校验ID，pData：数据指针，DataLen：数据长度
  * @retval 累加校验和
  */
uint8_t LIN_GetChecksum(uint8_t PID, uint8_t* pData,uint8_t DataLen) 			 
{  
	  uint16_t CheckSum = 0;  	
	  if ((PID!=0x3C)&&(PID!=0x7D)){    //诊断帧只能使用标准校验和，标准校验和不包含PID               	  
			CheckSum = PID;     		
	  }
	  for (uint8_t i = 0; i < DataLen; i++){
			CheckSum += pData[i];		  
			if (CheckSum > 0xFF){
				CheckSum -= 0xFF;  
			}
	  }
	  return (~CheckSum) & 0xFF;   
}


void Data_cnt(uint8_t FrameID, uint8_t* pData, LIN_MSG_IDType IDType)
{
	static uint8_t bitCounter = 0;

	if (IDType == MASTER_WRITE){
		switch (FrameID){
		case 0x01: 
			bitCounter++;
			bitCounter %= 0x10;
			*pData &= 0xF0;
			*pData |= bitCounter;					
			break;
		}
	}
}


/**
  * @brief  LIN消息发送		
  * @param  FrameID：帧ID，pData：数据指针，DataLen：数据长度，IDType：帧ID类型 
  * @retval None
  */
void LIN_SendMsg(USART_TypeDef* USARTx,uint8_t FrameID,uint8_t* pData,uint8_t DataLen, LIN_MSG_IDType IDType)
{
	//检查数据长度是否符合LIN协议
	if (DataLen > 8){
		DataLen = 8;
	}
	//Data_cnt(FrameID,pData,IDType); 

	//同步段+PID+数据段(1~8)+校验和=(最大11个字节)
	uint8_t PID = LIN_GetPID(FrameID);	//获取PID
	uint8_t Checksum = LIN_GetChecksum(PID,pData,DataLen); //获取校验和
	uint8_t Linbuffer[DataLen+3]; 			
    Linbuffer[0] = 0x55;
	Linbuffer[1] = PID;	
	switch (IDType){		
		case MASTER_BREAK: //同步间隔
			LIN_SendBreak(USARTx); 				
		 break;				
		case MASTER_WRITE:{ //主机写：发送帧头 + 响应
			if (DataLen > 0){
				USARTx->CR1 &= (uint16_t)(~(0x01 << 2));    //关闭串口接收
				for (uint8_t i = 0; i < DataLen; i++){
					Linbuffer[i + 2] = *(pData + i);		
				}	
				Linbuffer[DataLen + 2] = Checksum;	
				LIN_SendBreak(USARTx); 					
				LIN_SendBytes(USARTx, Linbuffer, DataLen+3);	//+3为同步段,PID和校验和
				while (LIN_RX_TimOut > 0);				 //等待主机接收完成				
				USARTx->CR1 |= (uint16_t)(0x01 << 2);    //打开串口接收
			}										
		}break;
		// 主机读：发送帧头，响应由其它从机节点发送(主机通过中断接收响应)
		case MASTER_READ:{									         					        							
			LIN_SendBreak(USARTx); 				
			LIN_SendBytes(USARTx, Linbuffer ,2); 			
			if (FrameID!=0x3D){
				LIN_RX_TimOut = Temp;
				LIN_TimOutCmd(TIM3, ENABLE); //使能定时器计数器
				while (LIN_RX_TimOut > 0);	 //等待主机接收完成		
			}					
		}break;							
	} 
}


	
/**
  * @brief  LIN主机接收处理函数,接收从机响应：数据 + 检验和
  * @param  LinMasterRxMsg:主机接收的数据字节,PID：主机发送的PID
  * @retval None
  */
void LIN_MasterRxMsg(uint8_t Data)
{
	LIN_MSG* pLINMsg = LIN_RingBUF_GetMsg(&LIN_RxDataBuff);
	
	switch (LIN_RxStateGet){
		case BREAK_GET:
			break;
		case SYNCH_GET:{
			pLINMsg->Sync = Data;
			LIN_RxStateGet = PID_GET;					
		}break;											
		case PID_GET:{
			pLINMsg->FrameID = Data&0x3F;
			pLINMsg->PID = Data;
			switch (FrameIDType[pLINMsg->FrameID]){			
				case MASTER_READ:			   //主机读取帧ID,主机写不采用中断					
					LIN_RxStateGet = MSG_GET;  //标志要在最后清除不能写在前面	
				break;	
				default:
					LIN_RxStateGet = BREAK_GET;						
				break;						
			}										
		}break;				
		case MSG_GET:{
			pLINMsg->Data[pLINMsg->DataLen++] = Data;
			pLINMsg->Checksum = Data;
			LIN_RxStateGet = (pLINMsg->DataLen>=8)?CHECKSUM_GET:MSG_GET;
		}break;	
		case CHECKSUM_GET:{
			pLINMsg->Checksum = Data;
			LIN_TimOutCmd(TIM3,DISABLE);				
		    LIN_RX_TimOut = -1;
			LIN_RingBUF_Write(&LIN_RxDataBuff);
			LIN_RxStateGet = BREAK_GET;			
		}break;
			default:
			LIN_RxStateGet = BREAK_GET;	
		break;
	}
}



/**
  * @brief  LIN主机中断函数
  * @param  None
  * @retval None
  */
void LIN_MASTER_IRQHandler(void)
{
	uint8_t ReceiveData = 0;
	//LIN断开帧中断
	if (USART_GetITStatus(USART1,USART_IT_LBD) == SET){			
		LIN_RX_TimOut = Temp; 	
		LIN_RingBUF_ClearRxMsg(&LIN_RxDataBuff);
        USART1->SR;  //验证能不能删除
        USART1->DR;	
		LIN_RxStateGet = SYNCH_GET;
		USART_ClearITPendingBit(USART1,USART_IT_LBD);
		return;		
	}
	if (USART_GetITStatus(USART1,USART_IT_RXNE) == SET){//LIN接收中断			
		ReceiveData = USART_ReceiveData(USART1);	
		if (USART_GetFlagStatus(USART1,USART_FLAG_FE) == RESET){
			if ((ReceiveData==0x55)&&(LIN_RxStateGet==BREAK_GET)){ //处理无同步间隔信号的LIN数据
				LIN_RX_TimOut = Temp;
				LIN_RingBUF_ClearRxMsg(&LIN_RxDataBuff);
				LIN_RxStateGet = SYNCH_GET;
			}			
			LIN_MasterRxMsg(ReceiveData);  
		}				
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);			
	}	
}




